iT邦幫忙

2024 iThome 鐵人賽

DAY 3
0
Mobile Development

從零開始以Flutter打造跨平台聊天APP系列 第 3

Day-3 Dart 簡介(2):List, Map 及 Null Safety

  • 分享至 

  • xImage
  •  

Generated from Stable Diffusion 3 Medium

昨天的教學,有教大家 Dart 的變數及流程控制,今天的教學則會說明一些常用的 collections,List 和 Map,並且會提到 Sound null Safety 的概念。在 Flutter 中,有很多地方都會用到 List,也因此掌握 List 的用法對 Flutter 至關重要!

程式碼:https://github.com/ksw2000/ironman-2024

參考官方教學: https://dart.dev.org.tw/language/collections

List

在 Dart 中,利用中括號代表 list,list 的型態為 List,也可以指定 List 中的型態,比如 List<String>, List<int> 等。並且我們可以利用 .add() 的方法追加元素在 List 後面,即 Javascript 中的 push()

var name = ['小櫻', '知世', '小狼'];
name.add('小可');
name.add('雪兔');
print(name);

// [小櫻, 知世, 小狼, 小可, 雪兔]

以下這幾種宣告空 list 的方法也是可行的

List<String> name2 = [];
List name3 = <String>[];

我們也可以利用 ... 來展開 List,使其加入再另一個 list 之後

// 除了用 var 判定型態也可以使用 List 自動判定
List group = ['小狼', '小櫻', '小可'];
List<String> group2 = ['知世', '雪兔', ...group];
print(group2);

// [知世, 雪兔, 小狼, 小櫻, 小可]

List 有一些常用的方法

var name = ['小櫻', '知世', '小狼'];
print(name.first); // 取得第一個元素:
print(name.isEmpty); // list 是否為空
print(name.isNotEmpty); // list 是否不為空
print(name.length); // 取得 list 長度
print(name.last); // 取得最後一個元素
print(name.reversed); // 反轉

//  小櫻
// false
// true
// 5
// 雪兔
// (雪兔, 小可, 小狼, 知世, 小櫻)

reverse() 回傳的是一個 Iterable 類,因此印出時是 () 而不是 []

另外,在走訪一個 list 時,有幾個方法,第一個就是大家最熟悉的方法,從第 0 個開始走訪到最後一個,另外也可以利用語法糖 for-in 的方式取得元素,最後也可以用類似 javascript 的 foreach + callback function 來走訪。在 Dart 中,當以 function 為 value 時,中間不用像 Javascript 加上 =>,直接加入花括號就可以執行了!

for (int i = 0; i < name.length; i++) {
    print(name[i]);
}

for (var n in name) {
    print(n);
}

name.forEach((element) {
    print("$element, ");
});

Map

在 Dart 中,利用花括號代表 map,我們可以直接建立一個空的 map,並利用鍵去賦值。

var first_publish = {};

first_publish['go'] = 2009;
first_publish['rust'] = 2010;
first_publish['kotlin'] = 2011;
first_publish['flutter'] = 2017;
print(first_publish);

// {go: 2009, rust: 2010, kotlin: 2011, flutter: 2017}

此時 first_publish 的型別為 Map<dynamic, dynamic>,什麼是 dynamic 呢?對於那些無法在編譯前確定的型別,我們都可以用 dynamic 表示,dynamic 可以告訴編譯器不做型別檢查,因此有可能在 runtime 會報錯。類似 typescript 中的 any;或者你可以認為在 // javascript 的世界裡全部的變數都是 dynamic

當然我們也可以在宣告一個非空的 map。此時編譯器可以自動判斷 first_publish2 的型別為 Map<String, int>

var first_publish2 = {
    'go': 2019,
    'rust': 2010,
    'kotlin': 2011,
    'flutter': 2017
};

以下這幾種宣告方法也是可行的:

var first_publish3 = <String, int>{};
Map<String, int> first_publish4 = {};

Map 有一些常用的方法

print(first_publish.keys); // 取得鍵的 Iterable 類
print(first_publish.values); // 取得值的 Iterable 類
print(first_publish.length); // 取得 map 長度
print(first_publish.isEmpty); // map 是否為空
print(first_publish.isNotEmpty); // map 是否非空

// (go, rust, kotlin, flutter)
// (2009, 2010, 2011, 2017)
// 4
// false
// true

我們可以利用 .addAll() 將其中一個 map 加入另一個 map 中

var other_first_publish = {
    'c': 1972,
    'c++': 1983,
    'python': 1991,
    'php': 1995,
    'java': 1995,
    'javascript': 1996
};
  
first_publish2.addAll(other_first_publish);
print(first_publish2);

// {go: 2019, rust: 2010, kotlin: 2011, flutter: 2017, c: 1972, c++: 1983, python: 1991, php: 1995, java: 1995, javascript: 1996}

至於要如何刪除 map 中的鍵值對呢?我們可以利用 .remove() 來實現

first_publish2.remove('php');
print(first_publish2);
// {go: 2019, rust: 2010, kotlin: 2011, flutter: 2017, c: 1972, c++: 1983, python: 1991, java: 1995, javascript: 1996}

我們也可以利用 forEach() 來做走訪,此時的 forEach() 內的 callback function 與 List 不同,Map 的 callback function 可以對應兩個變數 keyvalue

first_publish2.forEach((k, v) {
    print("$k -> $v");
});

// go -> 2019
// rust -> 2010
// kotlin -> 2011
// flutter -> 2017
// c -> 1972
// c++ -> 1983
// python -> 1991
// java -> 1995
// javascript -> 1996

Sound null Safety

當我們在 map 中嘗試取得一個不存在的鍵時,會回傳 nullnull 是一個很特別的存在。由於 null 的存在很容易導致在 runtime 時系統出錯,因此我們先前所教的宣告都不允許 null 出現,也不允許在宣告時不給值。比如以下程式會報錯:

int a;
print(a);
// Error: Non-nullable variable 'a' must be assigned before it can be used.

如果我們想要使變數能使用 null,我們僅需在型別後加入 ? 即可

int? a;
print(a);
// null

在介紹 List 時,我們利用 ...listA 使 listA 展開,加入另一個 List 中。假如 listA 是一個可為空的型別 List? 時,我們就不能直接使用 ... 將其展開,而必需改用 ...?...?listA 代表如果 listA

List? group3;
List group4 = ['知世', '雪兔', ...?group3];

在 Dart 中我們可以利用 ?. 來呼叫方法,當變數為 null 時會自動忽略。

List? group3;

group3?.add(10);
print(group3); // null

如果我們保證這些可為 null 的變數不為空時,也可以用 !. 來呼叫方法。但是一般不建議使用這個方法,因為這有可能導致 runtime 時發生錯誤。

List? group3;

group3!.add(10);
print(group3);
// Unhandled exception:
// Null check operator used on a null value

另外,Dart 也支援 ?? 語法糖 a ?? b,當 a 不為 null 時返回 a,反知返回 b

var a = null;
var b = 10;
print(a ?? b); // 10

?., !.?? 的用法跟 Typescript 雷同,也因此只要掌握其中一套語言,就可以融會貫通。


上一篇
Day-2 Dart 簡介(1):變數、流程控制
下一篇
Day-4 Dart 簡介(3):Function
系列文
從零開始以Flutter打造跨平台聊天APP25
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言